package com.simen.hellobytes.runtime;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.StringTokenizer;

/**
 * 辅助使用Runtime运行简单命令
 */
public class RuntimeHelper {

    private String[] cmdarray;
    /**
     * 环境参数
     */
    private String[] envp;
    /**
     * 运行目录
     */
    private File directory;

    private InputStream inputStream;
    private InputStream errorStream;
    private OutputStream outputStream;

    /**
     * 在命令运行结束后，关闭Runtime IO Stream
     */
    private boolean closeStreamAfterRead = false;

    private Process process;
    private String outputLog = "";
    /**
     * 0：运行成功
     * 其它值：运行失败
     */
    private Integer processCode = null;

    /**
     * 默认将“ \t\n\f”作为分隔符，拆分为数组
     *
     * @param command 命令或命令与参数的集合
     * @return 拆分后的数组
     */
    public static String[] splitCommand(String command) {
        StringTokenizer st = new StringTokenizer(command);
        String[] cmdarray = new String[st.countTokens()];
        for (int i = 0; st.hasMoreTokens(); i++)
            cmdarray[i] = st.nextToken();
        return cmdarray;
    }

    public static RuntimeHelper create(String command) {
        return new RuntimeHelper(splitCommand(command));
    }

    private RuntimeHelper(String[] cmdarray) {
        this(cmdarray, null, null);
    }

    public RuntimeHelper(String[] cmdarray, String[] envp, File dir) {
        this.cmdarray = cmdarray;
        this.envp = envp;
        this.directory = dir;
    }

    public RuntimeHelper exec() {
        try {
            execImpl();
        } catch (IOException | InterruptedException e) {
            outputLog = e.getMessage();
            return this;
        }

        readStream();
        return this;
    }

    private void readStream() {
        if (process == null) {
            return;
        }

        if ((processCode = process.exitValue()) == 0) {
            outputLog = new StreamInfoReader(inputStream)
                    .setCloseStreamAfterRead(closeStreamAfterRead)
                    .read()
                    .result();
        } else {
            outputLog = new StreamInfoReader(errorStream)
                    .setCloseStreamAfterRead(closeStreamAfterRead)
                    .read()
                    .result();
        }
    }

    private void execImpl() throws IOException, InterruptedException {
        process = Runtime.getRuntime().exec(cmdarray, envp, directory);

        inputStream = process.getInputStream();
        errorStream = process.getErrorStream();
        outputStream = process.getOutputStream();

        process.waitFor();
    }

    public String getOutputLog() {
        return outputLog;
    }

    public Integer getProcessCode() {
        return processCode;
    }

    public RuntimeHelper setCmdarray(String[] cmdarray) {
        this.cmdarray = cmdarray;
        return this;
    }

    public RuntimeHelper setEnvp(String... envp) {
        this.envp = envp;
        return this;
    }

    public RuntimeHelper setDirectory(File directory) {
        this.directory = directory;
        return this;
    }

    public String command() {
        StringBuilder command = new StringBuilder();
        for (int i = 0; cmdarray != null && i < cmdarray.length; i++) {
            command.append(" ").append(cmdarray[i]);
        }
        return command.toString();
    }

    public boolean isCloseStreamAfterRead() {
        return closeStreamAfterRead;
    }

    public RuntimeHelper setCloseStreamAfterRead(boolean closeStreamAfterRead) {
        this.closeStreamAfterRead = closeStreamAfterRead;
        return this;
    }
}
